package com.bwie.service;


import com.bwie.bo.SpuBo;
import com.bwie.client.BrandClient;
import com.bwie.client.CategoryClient;
import com.bwie.client.GoodsClient;
import com.bwie.client.SpecClient;
import com.bwie.pojo.*;
import com.bwie.repository.GoodsRepository;

import com.bwie.utils.PageResult;

import org.apache.commons.lang.StringUtils;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;


import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchService {


    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private SpecClient specClient;

   @Autowired
   private GoodsService goodsService;

   @Autowired
   private BrandClient brandClient;

   @Autowired
   private CategoryClient categoryClient;



    @Autowired
    private GoodsRepository goodsRepository;




    public void batchGoodsList() throws Exception{
        //设定好分页 每一百条 批量插入一次
        Integer page = 1 ;
        Integer rows = 100 ;

       do {
           //分页查询数据
           PageResult<SpuBo> pageResult = goodsClient.findSpuList(page, rows, null, true);

           List<SpuBo> items = pageResult.getItems();
           List<Goods> goodsList = new ArrayList<>();
           for (SpuBo item : items) {
               Goods goods = goodsService.buildGoods(item);
               goodsList.add(goods);
           }


           goodsRepository.saveAll(goodsList);
           //获取当前页的数据条数，如果是最后一页，他肯定不满足100条
           rows= pageResult.getItems().size();
           //每次循环页码加1
            page++;
       }while (rows ==100) ;

    }


    public PageResult<Goods> search(SearchRequest searchRequest) {
        String key = searchRequest.getKey();
        if (StringUtils.isEmpty(key)){
            return null;
        }
        //编写构造的查询语句
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//        MatchQueryBuilder basicQuery = QueryBuilders.matchQuery("all", key).operator(Operator.AND);
        BoolQueryBuilder boolQueryBuilder = buildBoolQueryBuilder(searchRequest);


        queryBuilder.withQuery(boolQueryBuilder);
        //设置分页的参数
        Integer page = searchRequest.getPage(); // 1
        Integer size = searchRequest.getSize(); //20
        queryBuilder.withPageable(PageRequest.of(page-1,size));

        //排序
        String sortBy = searchRequest.getSortBy();
        Boolean descending = searchRequest.getDescending();
        if (StringUtils.isNotEmpty(sortBy)){
            queryBuilder.withSort(SortBuilders.fieldSort(sortBy).order(descending? SortOrder.DESC:SortOrder.ASC));
        }


        //进行查询。获取到结果，封装进行返回
        queryBuilder.withSourceFilter(new FetchSourceFilter(new  String[]{"id","skus","subTitle"},null));
/***************************聚合************************************************************************/
        String categoryAggName= "categories" ;
        String brandAggName = "brands";
        queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));
        queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));
/***************************聚合************************************************************************/

//        Page<GoodsEs> search = goodsRespsitory.search(queryBuilder.build());

        AggregatedPage<Goods> search = (AggregatedPage<Goods>) goodsRepository.search(queryBuilder.build());
        //获取商品分类的数据吧
        List<Map<String,Object>> categories = getCategoryAggResult(search.getAggregation(categoryAggName));
        //获取品牌名称的数据
        List<Brand> brands = getBrandAggResult(search.getAggregation(brandAggName));
/***************************聚合************规格参数的聚合************************************************************/
        //判断分类聚合的结果集大小 ，如果等于1 则聚合
        List<Map<String,Object>> specs = null;
        if (categories.size()==1){
            specs = getParamAggResult((Long) categories.get(0).get("id"),boolQueryBuilder);
        }
/****************************************************************************************************************/




        //计算总条数
        Long total = search.getTotalElements();
        // 180条数据 每页20条 问 一共多少页 = 9 页
        //187条数 每页20条 问一共多少页 10页
        int totalPage =   (total.intValue()+size-1)/size;

        return new SearchResult(search.getContent(),total, (long) totalPage,categories,brands,specs);

    }

    /**
     * 构造编译条件
     * @param searchRequest
     * @return
     */
    private BoolQueryBuilder buildBoolQueryBuilder(SearchRequest searchRequest) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //添加基本条件
        boolQueryBuilder.must(QueryBuilders.matchQuery("all",searchRequest.getKey()).operator(Operator.AND));

        //添加过滤条件
        if (CollectionUtils.isEmpty(searchRequest.getFilter())){
            return boolQueryBuilder;
        }

        for (Map.Entry<String, String> entry : searchRequest.getFilter().entrySet()) {
            String key = entry.getKey();
            //如果过滤条件中是 品牌 过滤的字段是brandId
            if (StringUtils.equals("品牌",key)){
                key = "brandId";
            }else if (StringUtils.equals("分类",key)){
                key="cid3";
            }else {
                key="specs."+key+".keyword" ;
            }
            boolQueryBuilder.filter(QueryBuilders.termQuery(key,entry.getValue()));
        }


        return boolQueryBuilder;
    }

    /**
     * 获取规格参数聚合
     * @param id
     * @param basicQuery
     * @return
     */
    private List<Map<String, Object>> getParamAggResult(Long id, BoolQueryBuilder basicQuery) {
        //创建自定义查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //基于基本的查询条件， 聚合规格参数
        queryBuilder.withQuery(basicQuery);
        //查询要聚合的规格参数去数据库中查询
        List<SpecParam> specParams = specClient.findSpecParamList(null, id, null, true);

        //添加聚合
        specParams.forEach(param->{
            queryBuilder.addAggregation(AggregationBuilders.terms(param.getName()).field("specs."+param.getName()+".keyword"));
        });
        //只需要聚合的结果，不需要查询的结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{},null));

        //执行聚合查询
        AggregatedPage<Goods> goodsPage = (AggregatedPage<Goods>) goodsRepository.search(queryBuilder.build());

        //定义一个集合，聚合的结果集
        List<Map<String, Object>> paramMapList  =  new ArrayList<>();
        //解析数据
        Map<String, Aggregation> aggregationMap = goodsPage.getAggregations().asMap();
        for (Map.Entry<String, Aggregation> entry : aggregationMap.entrySet()) {
            Map<String, Object> map = new HashMap<>();
            //放入规格参名称
            map.put("k",entry.getKey());
            //收集规格参数值
            List<Object> options =  new ArrayList<>();
            //解析每一个聚合
            Terms terms = (Terms) entry.getValue();
            //遍历每一个桶内的数据，把key放入收集规格参数集合中
            terms.getBuckets().forEach(bucket -> options.add(bucket.getKeyAsString()));
            map.put("options",options);
            paramMapList.add(map);
        }

        return paramMapList;
    }

    /**
     * 获取聚合中的商品品牌的名称
     * @param aggregation
     * @return
     */
    private List<Brand> getBrandAggResult(Aggregation aggregation) {
        Terms terms = (Terms) aggregation;
        //获取所有的分类的id桶
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        List<Brand> brands =  new ArrayList<Brand>();
        buckets.forEach(bucket -> {
            long brandId = bucket.getKeyAsNumber().longValue();
            //因为是对象，所以我们需要去数据库中查询当前对象的数据
            Brand brandInfo = brandClient.queryBrandNameByBrandId(brandId);
            brands.add(brandInfo);
        });

        return brands;
    }

    private List<Map<String, Object>> getCategoryAggResult(Aggregation aggregation) {
        Terms terms = (Terms) aggregation;
        //获取所有的分类的id桶
        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        List<Map<String, Object>> categories =  new ArrayList<>();
        List<Long> cids =   new ArrayList<Long>();
        //解析所有的id桶，查询商品分类对象
        buckets.forEach(bucket -> {
            cids.add(bucket.getKeyAsNumber().longValue()) ;
        });

        if (!CollectionUtils.isEmpty(cids)){

            List<String> names = categoryClient.queryNamesByIds(cids);
            for (int i = 0; i < cids.size(); i++) {
                Map<String, Object> map =new HashMap<>();
                map.put("id",cids.get(i));
                map.put("name",names.get(i));
                categories.add(map);

            }
        }
        return categories;
    }


}
